/**
 * PID算法
 *
 * 不使用中断，考虑到复杂性、可扩展性、可重入性和延时。
 *
 * 如果把程序移植到与视觉共用同一个单片机，则必须使用中断，因为视觉计算一帧的时间太长了。
 */
#ifndef PID_H
#define PID_H

#include <stdint.h>

typedef struct Pid_HandleTypeDef {
  uint32_t ti;       // 采样时间间隔（ms）参考值，实际值不低于参考值
  float kp, kd, ki;  // 三个控制参数
  float max_intg;    // 积分限幅
  float max_out;     // 输出限幅
  float target;      // 目标值
  float alpha;       // 输出滤波系数，范围0~1，值越大滤波越严重

  float intg;        // 积分（在v2中是积分项）
  float last_error;  // 上次误差
  float last_real;   // 上次实际值
  float out;         // 输出，或称为上次输出，v2中用于输出滤波。也可用于读取PID输出
} Pid_HandleTypeDef;

// 初始化PID
int Pid_Init(Pid_HandleTypeDef *handle, uint32_t ti, float kp, float ki,
             float kd, float max_intg, float max_out, float target, float alpha);
void Pid_SetTi(Pid_HandleTypeDef *handle, uint32_t ti);
void Pid_SetK(Pid_HandleTypeDef *handle, float kp, float ki, float kd);
void Pid_SetMax(Pid_HandleTypeDef *handle, float max_intg, float max_out);
void Pid_SetTarget(Pid_HandleTypeDef *handle, float target);
void Pid_SetAlpha(Pid_HandleTypeDef *handle, float alpha);
// 更新PID数据：计算并更新输出
float Pid_Calc(Pid_HandleTypeDef *handle, float reality);
float Pid_Calc2(Pid_HandleTypeDef *handle, float reality);
#endif
